package alibaba.timertask;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author ChangLiang
 * @date 2020/4/20
 */
@Slf4j
public class ScheduledExecutorServiceTest {

    @Test
    @DisplayName("test solution2 logic")
    public void test() {
        // 看起来其用法也是一个线程来驱动的
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

        scheduledExecutorService.scheduleAtFixedRate(()->{
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("do execute");}, 1, 1, TimeUnit.SECONDS);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static ThreadLocal<Long> threadLocalCount = ThreadLocal.withInitial(() -> 0L);

    /**
     * 不同的thread 其持有的threadLocal是不同的
     */
    @Test
    public void test2() {
        Runnable runnable = () -> {
            threadLocalCount.set(threadLocalCount.get() + 1);
            log.info("threadLocalCount:{}", threadLocalCount.get());
        };

        // 看起来其用法也是一个线程来驱动的
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

        scheduledExecutorService.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS);

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test3() {

        /**
         * 与TimerTask类似，其也是使用一个线程来执行这两个任务的
         * 不同的是 thread2 由于抛出了没有捕获的异常 退出了 而且并没有抛出异常堆栈
         * 但是 thread1 仍旧执行完成
         */

        Runnable runnable = () -> {
            threadLocalCount.set(threadLocalCount.get() + 1);
            log.info("threadLocalCount:{}", threadLocalCount.get());
        };

        Runnable runnable2 = () -> {
            threadLocalCount.set(threadLocalCount.get() + 1);
            if (threadLocalCount.get().equals(6L)) {
                int a = 1 / 0;
            }
            log.info("threadLocalCount:{}", threadLocalCount.get());
        };

        // 看起来其用法也是一个线程来驱动的
        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

        scheduledExecutorService.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS);
        scheduledExecutorService.scheduleAtFixedRate(runnable2, 1, 1, TimeUnit.SECONDS);

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Test
    @DisplayName("thread local是线程私有的")
    public void test4() throws InterruptedException {
        Set<Long> set = Collections.synchronizedSet(new HashSet<>());
        List<Long> list = Collections.synchronizedList(new LinkedList<>());
        IntStream.range(0,100).forEach(i->new Thread(()->{
            long l = threadLocalCount.get() + 1;
            threadLocalCount.set(l);
            log.info("threadLocalCount:{}",threadLocalCount.get());
            set.add(l);
            list.add(l);
        },"my-thread-"+i).start());
        TimeUnit.SECONDS.sleep(5);
        log.info("set size:{}",set.size());
        log.info("list size:{}", list.size());
    }
}
